import React, {
  useState,
  createContext,
  useRef,
  useEffect,
  useMemo,
  useContext,
  useCallback,
} from "react";
import { cloneDeep, findIndex, isEmpty, last } from "lodash";
import {
  CHAT_ACTION,
  CHAT_ROLE,
  DEFAULT_ERROR_ITEM,
  DEFAULT_Q_LIST,
  DEVICE_TYPE,
  IChatHistoryItem,
  SESSION_TYPE,
  chatPageSize,
  parseMessage,
} from "@/utils/chat";
import {
  dataAnalysis,
  default_scene,
  deviceAnomalyDetection,
  generateUuid,
  offlineData,
  pid,
} from "@/utils/common";
import { fetchGenSessionTitle, IToFeedBackParams } from "./services/index";
import { fetchEventSource } from "@microsoft/fetch-event-source";
import ChatTool from "./Tool";
import useSession from "./useSession";
import useAction from "./useAction";
import { IQItem } from "./type";
import { message } from "antd";
import store from "store2";
import { fetchRefreshToken } from "@/services/supcon-chat-tool/api/app";
import { useGlobalData } from "./chat";
import { REQ_FAIL_ERROR_MSG } from "@/utils/request";
import { default_ask } from "@/utils/text";
import { BigScreenContext } from "./BigScreenContext";

const dayjs = require("dayjs");
interface IChatContextProps {
  isLoading: boolean;
  qList: Array<IQItem>;
  showChatList: Array<IQItem>;
  /**
   * @value 当前输入的问题
   */
  value: string;
  /**
   * @viewContent 当前正在回答问题的内容
   */
  viewContent: Partial<IQItem>;
  /**
   * @talkLists 当前会话历史数组
   */
  talkLists: Array<IChatHistoryItem>;
  /**
   * @selectTalk 当前对话上下文
   */
  selectTalk: any;
  overlayVisible: boolean;
  imagePreviewVisible: boolean;
  imagePreviewUrl: { src: string }[];
  typedLoadingRef: any;
  chatResourceOlTagBoxRef: any;
  showActionLogList: string[];
  showActionFileList: string[];
  footerExtraPupVisible: boolean;
  footerExtraOpVisible: boolean;
  footerExtraOpPupVisibleContent: any;

  setIsLoading: (loading: boolean) => void;
  setQList: (list: any[]) => void;
  setValue: (str: string) => void;
  handle: (v?: string, addReqObj?: IAddReqObj, cb?: any) => void;
  reLoad: (item: IQItem, fast?: boolean) => void;
  toPlay: (item: IQItem) => void;
  cancelAsk: () => void;
  toFeedback: (info: IToFeedBackParams) => void;
  setViewContent: (content: Partial<IQItem>) => void;
  createGroup: () => Promise<void>;
  onHandleChangeTalk: (
    type: string,
    selectTalk: IChatHistoryItem,
    cb?: (info?: any) => void
  ) => void;
  updateTask: (task: any) => void;
  updateChatSome: (
    id: string,
    content: Partial<IQItem>,
    list?: Array<IQItem> | null,
    checkTablePreview?: boolean
  ) => void;
  handleImagePreviewVisible: (list: { src: string }[]) => void;
  closeImagePreview: () => void;
  batchUpdateChatSomeSpeakingFalse: (update?: boolean) => void;
  updateScrollTop: (target?: boolean) => void;
  handleActionLogList: (id: string) => void;
  handleActionFileList: (id: string) => void;
  changeTargetHistoryByType: ({
    type,
    init,
  }: {
    type: string;
    init?: boolean;
  }) => void;
  setFooterExtraOpVisible: React.Dispatch<React.SetStateAction<boolean>>;
  setFooterExtraPupVisible: React.Dispatch<React.SetStateAction<boolean>>;
  setFooterExtraOpPupVisibleContent: React.Dispatch<React.SetStateAction<any>>;
  clearChatEffect: () => void;
  changeSession: (session: any) => void;
  resetRecommend: (id: any, params?: any) => void;
  isVoice: boolean;
  startVoice: () => void;
  endVoice: () => void;
  changeInputMethod: () => void;
  voiceKeyDownHanlder: (e: any) => void;
  voiceKeyUpHanlder: (e: any) => void;
  voiceStatus: "init" | "start" | "load" | "end";
}

export interface IAddReqObj {
  /**
   * @add 是否加入数组? 重新提问
   */
  add?: boolean;
  /**
   * @newChat 是否加强制新增
   */
  newChat?: boolean;
  /**
   * @list 当前数组
   */
  list?: Array<IQItem>;
  /**
   * @action 操作逻辑
   */
  action?: CHAT_ACTION;
  /**
   * @msgId  msgId
   */
  msgId?: string;
  /**
   * @parentMsgId 前置 parentMsgId
   */
  parentMsgId?: string;
  scene?: any;
}

interface IChatSourceMap {
  id?: IQItem;
}

export const ChatContext = createContext<IChatContextProps>(
  {} as IChatContextProps
);

export const useChatContextProvider = (
  props: IIndexContext
): IChatContextProps => {
  const {
    // chatScene,
    // chatMemo,
    chatOlTag,
    chatMemoRef,
    footerExtraPupVisible,
    setFooterExtraPupVisible,
    footerExtraOpPupVisibleContent,
    setFooterExtraOpPupVisibleContent,
    footerExtraOpVisible,
    setFooterExtraOpVisible,
    // setChatOlTag,
    think,
    hyzsTarget,
  } = useGlobalData();
  const { setCurrentKey, initNavList } = useContext(BigScreenContext);
  // const { footerExtraOpVisible, setFooterExtraOpVisible } = useFooterExtraOp();

  // 回到底部
  const { scrollDomRef, scrollToBottom } = props;

  // 回答 图片预览
  const [imagePreviewUrl, setImagePreviewUrl] = useState<{ src: string }[]>([]);
  const [imagePreviewVisible, setImagePreviewVisible] =
    useState<boolean>(false);

  // 其他网络
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
  const [isNetLoading, setIsNetLoading] = useState<boolean>(false);
  // 对话
  const [isLoading, setIsLoading] = useState<boolean>(false);
  const [isVoice, setIsVoice] = useState<boolean>(false);
  const [voiceStatus, setVoiceStatus] = useState<
    "init" | "start" | "load" | "end"
  >("init");
  const voiceTypeRef = useRef<"key" | "point" | "none">("none");

  const typedLoadingRef = useRef<any>(null);
  const chatResourceOlTagBoxRef = useRef<any>(null);

  // 蒙层
  const [overlayVisible, setOverlayVisible] = useState<boolean>(false);

  // 当前缓存的对话上下文
  const [qList, setQList] = useState<Array<IQItem>>(DEFAULT_Q_LIST as any);
  // console.log('qList',qList);
  // 对话记录分页
  const [currentChatPage, setCurrentChatPage] = useState<number>(1);
  const currentChatPageRef = useRef<number>(1);
  const pageChangeRef = useRef<boolean>(false);
  const preScrollPosition = useRef<{
    scrollTop: number;
    scrollHeight: number;
  }>();
  const totalListRef = useRef<{
    total: number;
  }>({ total: 0 });

  // ! 输入的问题
  const [value, setValue] = useState<string>("");

  // ! 当前正在生成的回答
  const [viewContent, setViewContent] = useState<Partial<IQItem>>({});

  // 提问: 回答 缓存对象
  const chatSourceMapRef = useRef<IChatSourceMap>({});

  // 缓存当前再chunk 的对话
  const chunkCacheInfoRef = useRef<any>({});
  // 当前对话对象
  const requestTaskRef = useRef<any>(null);

  const changeChatSourceMapRef = (currentChatSourceMap: any) => {
    chatSourceMapRef.current = currentChatSourceMap;
  };

  const updateScrollTop = (ignoreShowBack = false) => {
    if (ignoreShowBack) {
      scrollToBottom?.();
    } else {
      // ! 这边主要是实现 在当前视口用户不在底部的时候要不要主动滚动到底部 的 两个方式:
      // 1. 用户问了问题,然后在焦距其他问题的回答这个时候主动滚动会打断施法
      // 2. 回答完直接滚动到底部
      // ? 是否要焦距当前
      // if (!showBack) {
      //   // 在当前回答则自动滚动到底部, 不然就是在看其他内容
      //   scrollToBottom?.();
      // }

      // 直接滚动底部
      scrollToBottom?.();
    }
  };

  /**
   * @description: 操作中的中断提示逻辑
   * @return {*}
   */
  const loadingActionFb = () => {
    message.info("Loading...");
    return;
  };

  /**
   * @description: 更新对话 数组: 涉及到修改一些项目的字段,如是否当前项目在播放音频
   * @param {string} id 项 id
   * @param {Partial} content 更新 内容
   * @return {*}
   */
  const updateChatSome = (
    id: string,
    content: Partial<IQItem>,
    list?: Array<IQItem> | null,
    checkTablePreview?: boolean
  ) => {
    console.log("updateChatSome id", id, content);
    console.log("updateChatSome checkTablePreview", checkTablePreview);
    let cChatList = list || [...qList];

    let updateIndex = findIndex(cChatList, (item) => {
      return item.id === id;
    });
    // 如果找到了项，更新它的age属性
    if (updateIndex > -1) {
      // 判断是否是表格预览，如果是则不更新内容，直接返回
      // 涉及到报表 image 的实现逻辑
      if (checkTablePreview) {
        if (cChatList[updateIndex]["tablePreview"]) {
          console.log("判断是否是表格预览");
          return;
        }
      }

      let cData = cChatList[updateIndex];
      cData = {
        ...cData,
        ...content,
      };
      cChatList[updateIndex] = {
        ...cData,
      };
    }
    console.log("updateChatSome cChatList", cChatList);
    setQList([...cChatList]);
  };

  /**
   * @description: scene 参数构造
   * @param {*} sessionId
   * @param {any} cReq
   * @return {*}
   */
  const reqAdapterByMemo = (sessionId = "", cReq: any) => {
    let currentScene = chatMemoRef?.current?.[sessionId] ?? default_scene;
    let newScene = cloneDeep(currentScene);
    let params = newScene?.["params"] ?? {};
    Reflect.deleteProperty(params, "app_ids");
    Reflect.deleteProperty(params, "data_insight");
    newScene = {
      ...newScene,
      params,
    };

    console.log("newScene", newScene);
    if (newScene.id) {
      if (newScene.id === "knowledgeBase") {
        // AI考试特殊处理
        if (chatOlTag.id === 2) {
          let kb_info_list = newScene.params?.kb_info_list ?? [];
          let newparams = {
            file: kb_info_list[0] ?? {},
          };

          newScene = {
            ...newScene,
            id: "zswd",
            name: "zswd",
            type: "zswd",
            params: newparams,
          };
        }
        // let kb_ids = newScene?.['params']?.['kb_ids'] ?? [];

        // let params = {
        //   kb_info_list: kb_ids
        // };
        // let cScene = {
        //   ...newScene,
        //   params,
        // }
        // // knowledgeBase 处理一下 kb_info_list
        // return {
        //   ...cReq,
        //   scene: cScene
        // };
        return {
          ...cReq,
          scene: newScene,
        };
      } else if (newScene.id === offlineData) {
        // offlineData params 需要 file 包裹一下
        let offlineDataParams = {
          file: {
            ...params,
          },
        };
        let cScene = {
          ...newScene,
          params: offlineDataParams,
        };
        return {
          ...cReq,
          scene: cScene,
        };
      } else if (newScene.id === dataAnalysis) {
        // pid params 需要 分为 pidFile 和 pidParams
        // pidFile 是选择的文件
        // pidParams 是配置参数
        const { dataType, fileParams, ...rest } = params;
        let cScene = { ...newScene };
        // 稳态检测特殊处理
        if (dataType === "balance") {
          let configParams = {
            file: {
              ...rest,
            },
            fileParams,
          };
          cScene = {
            ...newScene,
            params: configParams,
          };
        }
        return {
          ...cReq,
          scene: cScene,
        };
      } else if (newScene.id === pid) {
        // pid params 需要 分为 pidFile 和 pidParams
        // pidFile 是选择的文件
        // pidParams 是配置参数
        const { pidParams: configParams, ...rest } = params;
        let pidParams = {
          pidFile: {
            ...rest,
          },
          pidParams: {
            ...configParams,
          },
        };
        let cScene = {
          ...newScene,
          params: pidParams,
        };
        return {
          ...cReq,
          scene: cScene,
        };
      } else if (newScene.id === deviceAnomalyDetection) {
        // 设备异常 params 需要 包含 file
        let sbycParams = {
          file: {
            ...params,
          },
        };
        let cScene = {
          ...newScene,
          params: sbycParams,
        };
        return {
          ...cReq,
          scene: cScene,
        };
      } else {
        return {
          ...cReq,
          scene: newScene,
        };
      }
    } else if (hyzsTarget) {
      let scene = {
        id: "knowledgeBase",
        name: "knowledgeBase",
        type: "knowledgeBase",
        params: {
          kb_info_list: [
            {
              kb_id: "KB25eab8aac0794632b4ef215fbe58b3c3",
              user_id: "admin", // 这边是写死的
            },
          ],
        },
      };
      return {
        ...cReq,
        scene: scene,
      };
    } else {
      return {
        ...cReq,
      };
    }
  };

  /**
   * @description: 提问
   * @param {*} voiceTvalue 语音输入内容
   * @param {*} addReqObj 提问额外参数
   * @return {*}
   */
  const handle = async (
    voiceTvalue = "",
    addReqObj: IAddReqObj = {},
    cb?: any
  ) => {
    // 取消插件
    if (!isEmpty(chatOlTag)) {
      chatResourceOlTagBoxRef?.current?.handleCloseConfig?.();
    }

    const cValue = voiceTvalue || value;
    const {
      add = true,
      parentMsgId = "",
      msgId: pMsgId = "",
      action = CHAT_ACTION.next,
      list = [],
      scene: orgScene = null,
      newChat = false,
    } = addReqObj;
    console.log("handle addReqObj", addReqObj);
    console.log("handle cValue", cValue);
    // console.log("handle isLoading", isLoading);

    if (isLoading) {
      cb?.();
      return message.info("正在处理上一个问题...");
    }
    if (!cValue) {
      cb?.();
      return message.info("请输入内容");
    }

    if (typeof cValue === "string" && cValue.includes(default_ask)) {
      // 切换首页场景
      setCurrentKey("question");
      initNavList();
    }
    toStopAsk();
    setViewContent({});

    setIsLoading(true);
    const reqValue = cValue;

    setTimeout(() => {
      setValue("");
    }, 100);

    // 获取 当前 session 和是否 是新会话
    const [sessionId, isNew] = await addSession(reqValue);

    if (!sessionId) {
      setIsLoading(false);
      cb?.();
      // TODO: 这边要把 memo 中 new_session 替换为真实的
      return;
    }
    // console.log('handle qList', qList);
    // console.log('handle list', list);

    let cList: any = newChat ? [] : add ? [...qList] : [...list];
    // let cList: any = [...list];
    // const respList = cList.filter((item) => item.role === CHAT_ROLE.view)
    const respList = cList.filter((item) => item.id && !item.isInitChat);
    const msgId = generateUuid();
    const options: IQItem = last(respList) ?? ({} as IQItem);
    // console.log('handle msgId', msgId);
    // console.log('handle cList', cList);

    // console.log('handle options', options);

    const pParentMsgId = parentMsgId || options.id || "0";

    let reqData: any = {
      action: action,
      contents: [
        { content: reqValue, contentType: "text", role: CHAT_ROLE.user },
      ],
      msgId: pMsgId || msgId,
      deviceType: DEVICE_TYPE.app,
      parentMsgId: pParentMsgId,
      sessionId: sessionId,
      sessionType: SESSION_TYPE.text_chat,
      pluginIds: [],
      think: think,
    };
    // reqData = reqAdapter({
    //   req: reqData
    // })
    let scene = {};
    if (orgScene) {
      scene = orgScene;
      reqData = {
        ...reqData,
        scene: orgScene,
      };
    } else {
      reqData = reqAdapterByMemo(sessionId, reqData);
      scene = reqData?.scene ?? {};
    }

    const askInfo = {
      id: msgId,
      createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      msgId: msgId,
      childMsgId: [],
      messageBody: {
        contents: [
          {
            role: CHAT_ROLE.user,
            contentType: "text",
            content: reqValue,
          },
        ],
      },
      parentMsgId: pParentMsgId,
      sessionId: sessionId,
      scene,
    };
    // ! 加入回答中的 item
    const reqInfo = {
      id: `${msgId}-mock-req`,
      // id: `${msgId}`,
      createTime: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      msgId: msgId,
      childMsgId: [],
      messageBody: {
        contents: [],
      },
      parentMsgId: msgId,
      sessionId: sessionId,
      role: CHAT_ROLE.view,
      loading: "init",
    };
    if (add) {
      cList.push(askInfo);
      cList.push(reqInfo);
      setQList([...cList]);
    }
    // 提问后定位到下面
    updateScrollTop(true);

    ChatTool.newController();

    let token = store.get("token");
    // eslint-disable-next-line @typescript-eslint/no-unused-vars
    let adapterToken = store.get("adapterToken");

    let currentChatSourceMap = { ...chatSourceMapRef.current };
    // 生成中的回答暂时先加入数组
    console.log("提问加入对话缓存", askInfo);
    currentChatSourceMap[askInfo.msgId] = {
      ...askInfo,
    };
    // setChatSourceMap(currentChatSourceMap);
    chatSourceMapRef.current = currentChatSourceMap;
    let localeLang = "zh-CN";
    chunkCacheInfoRef.current = { ...reqInfo };
    setViewContent({ ...(reqInfo as any) });

    const headers = {
      "x-app": "gpt", // 自建应用
      accept: "application/json, text/plain, */*",
      "Content-Type": "application/json",
      "Accept-Language": localeLang,
    };
    if (token) {
      headers["Authorization"] =
        `Bearer ${token ? token.replace(/^"|"$/g, "") : ""}`;
    }

    let originData: any = {};
    const mergeMessageData = (mergeData: any) => {
      const messageKeys = [
        "msgId",
        "id",
        "messageBody",
        "sessionId",
        "parentMsgId",
      ];
      const thinkKeys = ["agentId", "agentName", "chatId"];
      const mergeKeys = Object.keys(mergeData);
      const isMessage = messageKeys.every((i) => mergeKeys.includes(i));
      const isThink = thinkKeys.every((i) => mergeKeys.includes(i));
      if (isMessage) {
        originData = mergeData;
      } else if (isThink) {
        if (originData.messageBody) {
          const newOriginData = cloneDeep(originData);
          if (newOriginData.messageBody.thinks) {
            const originThinks = newOriginData.messageBody.thinks;
            const findThinkIndex = originThinks.findIndex(
              (i: any) => i.agentId === mergeData.agentId
            );
            if (findThinkIndex === -1) {
              originThinks.push(mergeData);
              newOriginData.messageBody.thinks = originThinks;
            } else {
              const { leftContent, rightContent, ...other } = mergeData;
              const mergeItem =
                newOriginData.messageBody.thinks[findThinkIndex];
              newOriginData.messageBody.thinks[findThinkIndex] = {
                ...mergeItem,
                ...other,
                leftContent: mergeItem.leftContent + leftContent,
                rightContent: mergeItem.rightContent + rightContent,
              };
            }
          } else {
            newOriginData.messageBody.thinks = [mergeData];
          }
          originData = newOriginData;
        }
      }
    };

    fetchEventSource("/cnpc-web/chat-tool-chat/api/conversation", {
      method: "POST",
      headers: {
        ...headers,
      },
      body: JSON.stringify({
        data: reqData,
      }),
      signal: ChatTool.controller.signal,
      openWhenHidden: true,
      onopen: async (response: any) => {
        const contentType = response.headers.get("content-type");
        if (!contentType?.startsWith("text/event-stream")) {
          const reader = response.body.getReader();
          const result = await reader.read();
          const decoder = new TextDecoder();
          const field = decoder.decode(result.value);
          const res = JSON.parse(field);
          if (res.code === "A0230") {
            await fetchRefreshToken();
          }
          if (res && !res.success) throw res;
        }
      },
      onclose() {
        console.log("onclose");
        setIsLoading(false);
      },
      onerror(err) {
        setIsLoading(false);
        console.log("onerror error", err);
        ChatTool.controller.abort();
        throw err;
      },
      onmessage: (event: any) => {
        // console.log('onmessage e', event);
        const viewIndex = cList.findIndex((i) => i.role === CHAT_ROLE.view);
        // console.log('viewIndex', viewIndex);
        let resData: any = {};
        if (event.data === "[DONE]") {
          // ctrl.abort();
        } else if (event.event === "[PING]") {
          //ctrl.abort();
        } else if (event.event === "[ERROR]") {
          //ctrl.abort();
          let cData = {
            ...DEFAULT_ERROR_ITEM,
            ...chunkCacheInfoRef.current,
          };
          cData["messageBody"]["contents"][0]["content"] = event.data ?? "";
          originData = cData;
          setIsLoading(false);

          return message.error("请求失败");
        } else if (event.event === "[MESSAGE]") {
          if (event.data) {
            resData = parseMessage(event.data);
            mergeMessageData(resData);
          }
        }
        chunkCacheInfoRef.current = {
          ...originData,
          loading: "load",
        };
        // 更新问答缓存对象
        let currentChatSourceMap = { ...chatSourceMapRef.current };
        // 生成中的回答暂时先加入数组
        // console.log('生成中的回答暂时先加入数组', resData);
        currentChatSourceMap[originData.msgId] = {
          ...askInfo,
          msgId: originData.msgId,
          parentMsgId: pParentMsgId,
        };
        // setChatSourceMap(currentChatSourceMap);
        chatSourceMapRef.current = currentChatSourceMap;
        setViewContent({ ...originData });
        if (viewIndex !== -1) {
          cList[viewIndex] = { ...originData, role: CHAT_ROLE.view };
        } else {
          // if (!viewContent.id) {
          //   setViewContent({ ...resData });
          // }
          cList.push({ ...originData, role: CHAT_ROLE.view });
        }
        setQList([...cList]);
        // 回答中往下滚动
        scrollToBottom?.();
      },
    }).then(
      async () => {
        if (!chunkCacheInfoRef?.current?.id) {
          return;
        }
        cb?.();
        // reslove(history)
        let data = chunkCacheInfoRef.current;
        // ! 回答完毕后更新问答对象
        data["role"] = CHAT_ROLE.assistant;
        // if (data?.role === CHAT_ROLE.view) {
        //   data['role'] = CHAT_ROLE.assistant;
        // }
        // if (!data?.role) {
        //   data['role'] = CHAT_ROLE.assistant;
        // }
        if (sessionId && isNew) {
          await fetchGenSessionTitle({
            sessionId: sessionId,
            msgId: askInfo?.msgId,
          });
        }
        let currentChatSourceMap = { ...chatSourceMapRef.current };
        currentChatSourceMap[data.msgId] = {
          ...askInfo,
          msgId: data.msgId,
          parentMsgId: pParentMsgId,
        };
        // setChatSourceMap(currentChatSourceMap);
        chatSourceMapRef.current = currentChatSourceMap;

        addHistoryGroup(reqValue, sessionId);
        // 这里是成功调用完的 可以写去掉加载中等逻辑
        // 由于SSE特性，需要由用户端断开连接，所以在使用完毕时，需要调用requestTask.abort()断开连接
        setIsLoading(false);
        ChatTool.controller.abort();
        addToReqList(data, cList);
      },
      (err) => {
        setIsLoading(false);
        ChatTool.controller.abort();

        console.log("fail error", err);
        const { errMsg = "" } = err;
        if (errMsg === REQ_FAIL_ERROR_MSG.abort) {
          return;
        }
        message.error(
          // eslint-disable-next-line eqeqeq
          err.errMsg == REQ_FAIL_ERROR_MSG.timeout ? "请求超时" : errMsg
        );
        scrollToBottom();
      }
    );
  };

  const getSessionCb = (list: any[], cb?: any) => {
    // ! 这边不加 setTimeout 会导致原先回答的提问渲染在当前 内容上面
    onChangeChatPage(1);
    setQList([]);
    setTimeout(() => {
      setQList(list);
      cb?.();
    }, 200);
  };

  // 修改当前 list 中的对应id 的 推荐问题
  const resetChatRecommend = (id, list) => {
    let cList = qList.map((item) => {
      if (item.msgId === id) {
        let messageBody: any = item?.["messageBody"] ?? {};
        let recommended = messageBody?.["recommended"] ?? {};
        let cRecommended = {
          ...recommended,
          content: list,
        };
        messageBody["recommended"] = cRecommended;
        return {
          ...item,
          messageBody,
        };
      } else {
        return item;
      }
    });
    setTimeout(() => {
      setQList(cList);
    }, 200);
  };

  const {
    talkLists,
    selectTalk,
    updateTask,
    onHandleChangeTalk,
    createGroup,
    addHistoryGroup,
    addSession,
    changeTargetHistoryByType,
    changeSession,
    resetRecommend,
  } = useSession({
    handle,
    handleChangeSessionCb: changeChatSourceMapRef,
    setIsLoading: setIsNetLoading,
    getSessionCb: getSessionCb,
    resetChatRecommend: resetChatRecommend,
    updateScrollTop,
    setViewContent,
  });

  const {
    showActionLogList,
    showActionFileList,
    reLoad,
    toPlay,
    toFeedback,
    handleActionLogList,
    handleActionFileList,
  } = useAction({
    isLoading,
    overlayVisible,
    qList,
    chatSourceMapRef,
    selectTalk,
    loadingActionFb,
    setQList,
    updateChatSome,
    handle,
    setOverlayVisible,
  });

  /**
   * @description: 当前所有对话项 都不播放语音
   * @return {*}
   */
  const batchUpdateChatSomeSpeakingFalse = (updateList = false) => {
    let cChatList = [...qList].map((item) => {
      return {
        ...item,
        speaking: false,
      };
    });
    if (updateList) {
      setQList([...cChatList]);
    }
    return cChatList;
  };

  /**
   * @description: 停止回答的一些副作用的清除
   * @return {*}
   */
  const toStopAsk = () => {
    typedLoadingRef?.current?.stop?.();
    setIsLoading(false);
    requestTaskRef?.current?.abort?.();
    ChatTool.controller.abort();
  };

  /**
   * @description: 停止生成
   * @return {*}
   */
  const cancelAsk = async () => {
    message.info("停止生成");
    toStopAsk();
    setViewContent((prev) => {
      return {
        ...prev,
        cancelAsk: true,
      };
    });
  };

  /**
   * @description: 把回答信息加入展示队列
   * @param {IQItem} data 当前回答内容
   * @param {Array} cList 当前已经存在的队列
   * @return {*}
   */
  const addToReqList = (data: IQItem, cList: Array<IQItem> = []) => {
    console.log("addToReqList data", data);
    console.log("addToReqList cList", cList);
    let qList = [...cList];
    let len = qList.length;
    if (len) {
      qList[len - 1] = data;
    }
    setQList([...qList]);
    updateScrollTop();
  };

  /**
   * @description: 预览ImagePreview
   * @param {object} list 需要预览的列表
   * @return {*}
   */
  const handleImagePreviewVisible = (list: { src: string }[]) => {
    setImagePreviewUrl([...list]);
    setImagePreviewVisible(true);
  };

  const closeImagePreview = () => {
    // setImagePreviewUrl([]);
    setImagePreviewVisible(false);
  };

  const clearChatEffect = () => {
    ChatTool?.controller?.abort?.();
    chunkCacheInfoRef.current = {};
  };
  const onChangeChatPage = (page: number) => {
    setCurrentChatPage(page);
    currentChatPageRef.current = page;
  };

  const scrollToPrePos = () => {
    // if (chatRef.current && preScrollPosition.current && pageChangeRef.current) {
    //   const { scrollTop, scrollHeight } = preScrollPosition.current;
    //   const scrollHeightAfter = chatRef.current.scrollHeight;
    //   const scrollHeightDifference = scrollHeightAfter - scrollHeight;
    //   chatRef.current.scrollTop = scrollTop + scrollHeightDifference;
    //   preScrollPosition.current = undefined
    //   setTimeout(() => {
    //     pageChangeRef.current = false
    //   }, 1000)
    // }
    setTimeout(() => {
      pageChangeRef.current = false;
    }, 1000);
  };

  const changeInputMethod = () => {
    // if (inputMethod === 'voice') {
    //   const canChange = checkCanToKey()
    //   if (!canChange) return
    // }
    if (!isVoice) {
      setVoiceStatus("init");
    }
    setIsVoice(!isVoice);
  };

  const voiceKeyUpHanlder = useCallback(
    (e: any) => {
      if (isVoice && e.code === "Space" && voiceStatus === "start") {
        endVoice();
      }
      voiceTypeRef.current = "none"
    },
    [voiceStatus, isVoice]
  );

  const voiceKeyDownHanlder = useCallback(
    (e: any) => {
      console.log("voiceKeyDownHanlder isVoice", isVoice);
      console.log("voiceKeyDownHanlder e", e);
      if (
        isVoice &&
        e.code === "Space" &&
        !["start", "load"].includes(voiceStatus) &&
        voiceTypeRef.current === "none"
      ) {
        voiceTypeRef.current = "key";
        console.log("voiceKeyDownHanlder aaaa=>");
        startVoice();
      }
      // if (isVoice && e.code === "p" && voiceStatus === "start") {
      //   endVoice();
      // }
      // ! 这边是快捷键
      // if ((e.code === 'KeyK' || e.code === 'KeyO') && e.ctrlKey) {
      //     e.preventDefault()
      //     if (inputMethod === 'voice') {
      //         const canChange = checkCanToKey()
      //         if (canChange) setInputMethod('keyboard')
      //     } else {
      //       setIsVoice('voice')
      //     }
      // }
    },
    [voiceStatus, isVoice]
  );

  const startVoice = () => {
    if (isLoading) {
      message.error("正在对话，请先停止当前对话！");
      voiceTypeRef.current = "none";
      return;
    }
    ChatTool.startChatVoice({
      onMessage: (text) => {
        setValue(text);
        console.log("startChatVoice res", text);
      },
    }).then(
      () => {
        setVoiceStatus("start");
        setIsVoice(true);
      },
      (err) => {
        // setIsVoice(false)
        voiceTypeRef.current = "none";

        message.error(err.message || "语音识别异常");
      }
    );
  };

  const endVoice = () => {
    setVoiceStatus("load");

    ChatTool.endChatVoice().then((res) => {
      console.log("endChatVoice then", res);
      voiceTypeRef.current = "none";

      setIsVoice(false);
      // handle(res as string);
    });
  };

  useEffect(() => {
    scrollToPrePos();
  }, [currentChatPage]);
  // 展示的对话
  const showChatList = useMemo(() => {
    const listLen = qList.length;
    const startIndex = Math.max(0, listLen - currentChatPage * chatPageSize);
    return qList.slice(startIndex, listLen);
  }, [qList, currentChatPage]);

  // 分页逻辑处理
  useEffect(() => {
    pageChangeRef.current = false;
    totalListRef.current = {
      total: qList.length,
    };
  }, [qList]);

  useEffect(() => {
    const divElement = scrollDomRef.current as HTMLDivElement;
    const handleScroll = () => {
      const chatLen = totalListRef.current.total;
      const reset = chatLen - currentChatPageRef.current * chatPageSize;
      if (
        divElement.scrollTop <= 160 &&
        reset > 0 &&
        // !loadingRef.current &&
        !pageChangeRef.current
      ) {
        pageChangeRef.current = true;
        preScrollPosition.current = {
          scrollTop: divElement.scrollTop,
          scrollHeight: divElement.scrollHeight,
        };
        // if (ChatTool.status !== 'load') {
        //   ChatTool.resetStatus('load')
        // }
        onChangeChatPage(currentChatPageRef.current + 1);
      }
    };
    if (divElement) {
      divElement.addEventListener("scroll", handleScroll);
    }
    return () => {
      if (divElement) {
        divElement.removeEventListener("scroll", handleScroll);
      }
    };
  }, []);

  return {
    isLoading,
    typedLoadingRef,
    qList,
    value,
    viewContent,
    talkLists,
    selectTalk,
    overlayVisible,
    imagePreviewUrl,
    imagePreviewVisible,
    showActionLogList,
    footerExtraOpVisible,
    footerExtraOpPupVisibleContent,
    showChatList,
    chatResourceOlTagBoxRef,
    showActionFileList,

    setIsLoading,
    setQList,
    setValue,
    handle,
    reLoad,
    toPlay,
    cancelAsk,
    toFeedback,
    setViewContent,
    createGroup,
    onHandleChangeTalk,
    updateTask,
    updateChatSome,
    handleImagePreviewVisible,
    closeImagePreview,
    batchUpdateChatSomeSpeakingFalse,
    updateScrollTop,
    handleActionLogList,
    handleActionFileList,
    changeTargetHistoryByType,
    footerExtraPupVisible,
    setFooterExtraPupVisible,
    setFooterExtraOpVisible,
    setFooterExtraOpPupVisibleContent,
    clearChatEffect,
    changeSession,
    resetRecommend,
    isVoice,
    startVoice,
    endVoice,
    changeInputMethod,
    voiceKeyUpHanlder,
    voiceKeyDownHanlder,
    voiceStatus,
  };
};

interface IIndexContext {
  showBack: boolean;
  scrollIntoView: string;
  // onScrollToLower: () => void;
  // scrollToBottom: () => void;
  [key: string]: any;
}

// 聊天窗口底部固定 滚动位置
export const CHAT_SCROLL_VIEW_BOTTOM_FIXATION =
  "chat-scroll-view-bottom-fixation";
export const IndexContext = React.createContext<IIndexContext>(
  {} as IIndexContext
);
